/*
 * Date：10/23/18 10:15 PM
 * Author: guomw
 *
 */

package org.elanfox.intellicommunity.biz.service.core.equipment.impl;

import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.elanfox.intellicommunity.biz.dto.condition.LocatorCondition;
import org.elanfox.intellicommunity.biz.dto.equipment.LocatorSaveDTO;
import org.elanfox.intellicommunity.biz.entity.embeddable.LocatorInfo;
import org.elanfox.intellicommunity.biz.entity.equipment.LocatorAreaPO;
import org.elanfox.intellicommunity.biz.entity.equipment.LocatorPO;
import org.elanfox.intellicommunity.biz.entity.equipment.LocatorPO_;
import org.elanfox.intellicommunity.biz.entity.resident.StructurePO;
import org.elanfox.intellicommunity.biz.repository.equipment.LocatorRepository;
import org.elanfox.intellicommunity.biz.service.core.equipment.LocatorAreaService;
import org.elanfox.intellicommunity.biz.service.core.equipment.LocatorService;
import org.elanfox.intellicommunity.biz.service.core.resident.StructureService;
import org.elanfox.intellicommunity.biz.vo.LocatorVO;
import org.elanfox.intellicommunity.common.constant.ExcelConstant;
import org.elanfox.intellicommunity.common.ienum.EquipmentEnum;
import org.elanfox.intellicommunity.common.ienum.base.CodeDescEnumHelper;
import org.elanfox.intellicommunity.common.utils.ExcelHelper;
import org.elanfox.intellicommunity.data.base.base.AbstractSearchableCrudService;
import org.elanfox.intellicommunity.data.base.base.SpecificationAndSort;
import org.elanfox.intellicommunity.data.base.dto.BaseSaveDTO;
import org.elanfox.intellicommunity.data.base.dto.BaseSearchDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.persistence.criteria.Predicate;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * 定位器相关service
 *
 * @author loutianxi
 * @date 2019-12-05
 */
@Service
public class LocatorServiceImpl extends AbstractSearchableCrudService<LocatorPO, Integer> implements LocatorService {

    @Autowired
    private LocatorRepository repository;
    @Autowired
    private StructureService structureService;
    @Autowired
    private LocatorAreaService locatorAreaService;

    private static final String strTrue = "是";

    protected LocatorServiceImpl(LocatorRepository repository) {
        super(repository);
    }

    @Override
    protected SpecificationAndSort<LocatorPO> specificationAndSort(BaseSearchDTO condition) {
        LocatorCondition locatorCondition = (LocatorCondition) condition;
        Specification<LocatorPO> specification = (root, query, cb) -> {
            List<Predicate> predicates = new ArrayList<>();
            if (locatorCondition.getNo() != null) {
                predicates.add(cb.equal(root.get(LocatorPO_.no), locatorCondition.getNo()));
            }
            if (locatorCondition.getStatus() != null) {
                predicates.add(cb.equal(root.get(LocatorPO_.status), locatorCondition.getStatus()));
            }
            if (locatorCondition.getDismantleStatus() != null) {
                predicates.add(cb.equal(root.get(LocatorPO_.dismantleStatus), locatorCondition.getDismantleStatus()));
            }
            if (locatorCondition.getOnlineStatus() != null) {
                predicates.add(cb.equal(root.get(LocatorPO_.onlineStatus), locatorCondition.getOnlineStatus()));
            }
            if (locatorCondition.getVoltageStatus() != null) {
                EquipmentEnum.VoltageStatusEnum voltageStatus = CodeDescEnumHelper.getEnumTypeByCode(EquipmentEnum.VoltageStatusEnum.class, locatorCondition.getVoltageStatus());
                predicates.add(cb.equal(root.get(LocatorPO_.voltageStatus), voltageStatus));
            }
            if (locatorCondition.getType() != -1) {
                EquipmentEnum.TypeEnum type = CodeDescEnumHelper.getEnumTypeByCode(EquipmentEnum.TypeEnum.class, locatorCondition.getType());
                predicates.add(cb.equal(root.get(LocatorPO_.type), type));
            }
            if (locatorCondition.getBindingBaseStation() != null) {
                predicates.add(cb.equal(root.get(LocatorPO_.bindingBaseStation), locatorCondition.getBindingBaseStation()));
            }
            return cb.and(predicates.toArray(new Predicate[predicates.size()]));
        };

        Sort sort = new Sort(Sort.Direction.DESC, "createTime");

        return new SpecificationAndSort<>(specification, sort);
    }

    @Override
    public LocatorPO save(BaseSaveDTO saveDTO) {
        LocatorSaveDTO locatorSaveDTO = (LocatorSaveDTO) saveDTO;
        LocatorPO locatorPO = findById(locatorSaveDTO.getLocatorId());
        //根据卡号获取
        LocatorPO locatorPO1 = repository.findByNo(locatorSaveDTO.getNo());
        if (locatorPO == null) {
            if (locatorPO1 != null) {
                throw new IllegalStateException("定位器编号已经存在");
            }
            locatorPO = new LocatorPO();
            locatorPO.setBindingBaseStation(false);
            locatorPO.initStatus();
            locatorPO.setShow(true);
        } else {
            if (locatorPO1 != null && locatorPO1.getNo() != locatorPO.getNo()) {
                throw new IllegalStateException("定位器编号已经存在!");
            }
        }
        //设备相关属性
        locatorPO.setNo(locatorSaveDTO.getNo());
        locatorPO.setVersion(locatorSaveDTO.getVersion());
        EquipmentEnum.TypeEnum type = CodeDescEnumHelper.getEnumTypeByCode(EquipmentEnum.TypeEnum.class, locatorSaveDTO.getType());
        locatorPO.setType(type);
        locatorPO.setAlarmedImmediately(locatorSaveDTO.getAlarmedImmediately() == 1);
        locatorPO.setAlarmTemplate(locatorSaveDTO.getAlarmTemplate());
        LocatorInfo locatorInfo = new LocatorInfo();
        locatorInfo.setFloorNode(locatorSaveDTO.getFloorNode());
        locatorPO.setLocatorInfo(locatorInfo);
        locatorPO.setDescribe(locatorSaveDTO.getDescribe());
        return repository.save(locatorPO);
    }

    @Override
    public boolean updateEnable(Integer locationId) {
        LocatorPO locatorPO = findById(locationId);
        if (locatorPO != null) {
            return repository.updateEnableById(locationId, !locatorPO.isEnable()) > 0;
        }
        return false;
    }

    @Override
    public boolean updateEnable(Long no) {
        LocatorPO locatorPO = findByNo(no);
        if (locatorPO != null) {
            return repository.updateEnableByNo(no, !locatorPO.isEnable()) > 0;
        }
        return false;
    }

    @Override
    public boolean deleteByNo(Long no) {
        return repository.deleteByNo(no) > 0;
    }

    @Override
    public boolean updateDismantleStatus(Integer locationId) {
        LocatorPO locatorPO = findById(locationId);
        if (locatorPO != null) {
            return repository.updateDismantleStatusById(locationId, !locatorPO.isDismantleStatus()) > 0;
        }
        return false;
    }

    @Override
    public List<LocatorPO> findByStructureId(Integer structureId) {
        return repository.findByLocatorInfo_StructureId(structureId);
    }

    @Override
    public LocatorPO findByNo(Long no) {
        return repository.findByNo(no);
    }

    @Override
    public LocatorVO updateLocation(LocatorSaveDTO dto) {
        LocatorPO locatorPO = findByNo(dto.getNo());
        LocatorInfo locatorInfo = locatorPO.getLocatorInfo();
        locatorInfo.setStructureId(dto.getStructureId());
        locatorInfo.setLatitude(dto.getLatitude());
        locatorInfo.setLongitude(dto.getLongitude());
        locatorInfo.setAddress(dto.getAddress());
        //查询楼层信息
        StructurePO structurePO = structureService.findById(dto.getStructureId());
        locatorInfo.setImgUrl(structurePO.getMapUrl());
        save(locatorPO);
        //转化vo
        LocatorVO locatorVO = createLocatorVo(locatorPO);
        return locatorVO;
    }

    @Override
    public List<LocatorVO> findEquipment() {
        List<LocatorVO> list = new ArrayList<>();
        List<LocatorPO> locatorPOS = repository.findLocator();
        for (LocatorPO locatorPO : locatorPOS) {
            list.add(createLocatorVo(locatorPO));
        }
        return list;
    }

    @Override
    public List<LocatorVO> findLocatorVoByStrId(Integer structureId, Boolean show) {
        List<LocatorVO> list = new ArrayList<>();
        List<LocatorPO> locatorPOS;
        if (show != null && show) {
            locatorPOS = repository.findByLocatorInfo_StructureIdAndShowIsTrue(structureId);
        } else {
            locatorPOS = repository.findByLocatorInfo_StructureId(structureId);
        }
        for (LocatorPO locatorPO : locatorPOS) {
            list.add(createLocatorVo(locatorPO));
        }
        return list;
    }

    @Override
    public boolean updateShow(Integer locationId) {
        LocatorPO locatorPO = findById(locationId);
        if (locatorPO != null) {
            return repository.updateShow(locationId, !locatorPO.isShow()) > 0;
        }
        return false;
    }

    @Override
    public void lead(MultipartFile updateFile) throws IOException {
        POIFSFileSystem fs = new POIFSFileSystem(updateFile.getInputStream());
        HSSFWorkbook hssfWorkbook = new HSSFWorkbook(fs);
        List<List<ExcelHelper.CellDesc>> excelContent = ExcelHelper.readWorkbook(hssfWorkbook, "sheet1", 1, ExcelConstant.LOCATOR.length, 0);
        List<LocatorPO> locatorList = new ArrayList<>();
        if (excelContent != null) {
            for (List<ExcelHelper.CellDesc> r : excelContent) {
                if (r.get(0).getValue() == null) {
                    continue;
                }
                if (StringUtils.isEmpty(r.get(0).getValue().toString())) {
                    continue;
                }
                long locatorNo = Long.parseLong(r.get(0).getValue().toString().trim());
                LocatorPO locatorPO = findByNo(locatorNo);
                if (locatorPO == null) {
                    locatorPO = new LocatorPO();
                    locatorPO.initStatus();
                    locatorPO.setBindingBaseStation(false);
                    locatorPO.setLocatorInfo(new LocatorInfo());
                }
                locatorPO.setNo(locatorNo);
                locatorPO.setVersion(r.get(1).getValue().toString().trim());
                locatorPO.setType(CodeDescEnumHelper.getEnumTypeByCode(EquipmentEnum.TypeEnum.class, Integer.parseInt(r.get(2).getValue().toString().trim())));
                String floorNode = r.get(3).getValue().toString().trim();
                locatorPO.getLocatorInfo().setFloorNode(strTrue.equals(floorNode));
                String show = r.get(4).getValue().toString().trim();
                locatorPO.setShow(strTrue.equals(show));
                locatorPO.setDescribe(r.get(5).getValue().toString().trim());
                locatorList.add(locatorPO);
            }
            save(locatorList);
        }

    }

    @Override
    public long count(Long no) {
        return repository.countAllByEnableIsTrue();
    }

    @Override
    public List<LocatorPO> findPStructureLocator(Integer structureId) {
        //第一步获取父id
        StructurePO structurePO = structureService.findById(structureId);
        return repository.findLocatorpoByPStrId(structurePO.getPStructureId(), structureId);
    }

    @Override
    public void addToArea(Integer areaId, String... idArray) {
        LocatorAreaPO areaPO = locatorAreaService.findById(areaId);
        List<Integer> ids = new ArrayList<>();
        for (String id : idArray) {
            ids.add(Integer.valueOf(id));
        }

        repository.updateArea(areaPO, ids);
    }

    @Override
    public List<LocatorPO> findByArea(Integer areaId) {
        return repository.findByAreaPO_Id(areaId);
    }

    /**
     * 创建vo
     *
     * @param locatorPO
     * @return
     */
    private LocatorVO createLocatorVo(LocatorPO locatorPO) {
        LocatorVO vo = new LocatorVO();
        vo.setLocatorId(locatorPO.getLocatorId());
        vo.setLocatorInfo(locatorPO.getLocatorInfo());
        vo.setVersion(locatorPO.getVersion());
        vo.setAddress(locatorPO.getLocatorInfo().getAddress());
        vo.setNo(locatorPO.getNo());
        vo.setFloorNode(locatorPO.getLocatorInfo().getFloorNode() ? "是" : "否");
        vo.setShow(locatorPO.isShow());
        vo.setDesc(locatorPO.getDescribe());
        //如果绑定基站的定位器显示基站类型
        if (locatorPO.isBindingBaseStation()) {
            EquipmentEnum.TypeEnum type = locatorPO.getBaseStation().getType();
            vo.setTypeCode(type.getCode());
            vo.setTypeDesc(type.getDesc());
        } else {
            EquipmentEnum.TypeEnum type = locatorPO.getType();
            vo.setTypeCode(type.getCode());
            vo.setTypeDesc(type.getDesc());
        }
        return vo;
    }
}
